package beanstao.util.store;

import java.util.List;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import beanstao.util.Strings;
import beanstao.util.enums.operator.Comparison;
import beanstao.util.enums.operator.Logical;
import beanstao.util.store.database.Where;

import com.google.common.collect.Lists;

/**
 * 对键值及键值之间的比较运算符的对象的封装
 * 
 * @author beanstao@google.com 
 */
public class KV
{
	/**
	 * 获得一个KeyCharValue，未传递比较运算符，默认为“等于”
	 * 
	 * @param key
	 * @param value
	 * @return
	 */
	public static KV ME(final String key, final Object value)
	{
		return new KV(key, Comparison.Equal, value);
	}

	/**
	 * 快速创建类型，key为ID
	 * 
	 * @param value
	 * @return
	 */
	public static KV ID(final Object value)
	{
		return ME("id", value);
	}

	/**
	 * 当多个条件时，如取号时间，大于某时间，小于某时间，可以用本方法创建类型
	 * 
	 * @param items
	 * @param key
	 * @return
	 */
	public static KV ME(List<KVItem> items, String key)
	{
		return new KV(key, items);
	}

	/**
	 * 快速创建类型
	 * 
	 * @param key
	 * @param co
	 * @param value
	 * @return
	 */
	public static KV ME(final String key, final Comparison co, final Object value)
	{
		return new KV(key, co, value);
	}

	/**
	 * 重要：Web频繁调用的解析方法
	 * 
	 * @param key
	 * @param value
	 * @return
	 */
	public static KV parse(final String key, String value)
	{
		// 原始字符串：[{"comp":">=","value":"2010-11-01 00:00:00","logical":"and"}]
		Comparison co = Comparison.Equal;
		if (Strings.isEmpty(value))
			return KV.ME(key, co, "");

		value = value.trim();
		if (!Strings.isQuoteBy(value, '[', ']'))
			return KV.ME(key, co, value);

		JSONArray array = JSONArray.fromObject(value);
		if ((array == null) || (array.size() <= 0))
			return KV.ME(key, co, value);

		List<KVItem> items = Lists.newArrayList();
		for (int i = 0; i < array.size(); i++)
		{
			if (!(array.get(i) instanceof JSONObject))
				return KV.ME(key, co, value);
			JSONObject jo = (JSONObject) array.get(i);
			KVItem kvItem = new KVItem();
			kvItem.setKey(key);
			kvItem.setComparison(Comparison.parse(jo.getString("comp")));
			String vv = jo.getString("value");
			kvItem.setValue(vv);
			kvItem.setLogical(Enum.valueOf(Logical.class, jo.getString("logical").toUpperCase()));
			items.add(kvItem);
		}
		return new KV(key, items);
	}

	KV(final String key, final Comparison co, final Object value)
	{
		super();
		items = Lists.newArrayList();
		KVItem kvItem = new KVItem();
		kvItem.setKey(key);
		kvItem.setComparison(co);
		kvItem.setValue(value);
		kvItem.setLogical(Logical.AND);
		items.add(kvItem);
	}

	KV(final String key, List<KVItem> items)
	{
		super();
		this.items = items;
	}

	public List<KVItem> getItems()
	{
		return items;
	}

	public void setItems(List<KVItem> items)
	{
		this.items = items;
	}

	private List<KVItem> items = null;

	/**
	 * 获取键值
	 * 
	 * @return
	 */
	public String $Key()
	{
		if (this.isEmpty() || (null == items.get(0)))
			return "";
		return items.get(0).$Key();
	}

	/**
	 * 获取键值
	 * 
	 * @return
	 */
	public void setKey(final String key)
	{
		items.get(0).setKey(key);
	}

	/**
	 * 获取运算符
	 * 
	 * @return
	 */
	public Comparison $CO()
	{
		if (this.isEmpty() || (null == items.get(0)))
			return Comparison.Equal;
		return items.get(0).$Comparison();
	}

	/**
	 * 设置操作符
	 * 
	 * @return
	 */
	public void setOperator(final Comparison co)
	{
		items.get(0).setComparison(co);
	}

	/**
	 * 获取当前键值对象中的值
	 * 
	 * @return
	 */
	public Object $V()
	{
		if (this.isEmpty() || (null == items.get(0)))
			return "";
		return items.get(0).$Value();
	}

	/**
	 * 设置值
	 * 
	 * @return
	 */
	public void setValue(final Object value)
	{
		items.get(0).setValue(value);
	}

	public boolean isEmpty()
	{
		return items.size() <= 0;
	}

	@Override
	public int hashCode()
	{
		final int prime = 31;
		int result = 1;
		result = prime * result + ((items == null) ? 0 : items.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj)
	{
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (this.getClass() != obj.getClass())
			return false;
		KV other = (KV) obj;
		if (items == null)
		{
			if (other.items != null)
				return false;
		}
		else if (!items.equals(other.items))
			return false;
		return true;
	}

	@Override
	public String toString()
	{
		StringBuilder builder = new StringBuilder();
		if (items != null)
			builder.append(items);
		return builder.toString();
	}

	public void setWhere(Where sqlText)
	{
		if (items.size() <= 1)
			this.setSqlSubText(items.get(0), sqlText);
		else
			for (KVItem item : items)
				this.setSqlSubText(item, sqlText);
	}

	private void setSqlSubText(KVItem kvitem, Where sqlText)
	{
		switch (kvitem.$Logical())
		{
			case AND:
				sqlText.and(kvitem.$Key(), kvitem.$Comparison(), kvitem.$Value());
				break;
			case OR:
				sqlText.or(kvitem.$Key(), kvitem.$Comparison(), kvitem.$Value());
			default:
				break;
		}
	}

}
